#region

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web;
using System.Web.Http;
using log4net;
using xConnected.Common.ExpertProfile;
using xConnected.Core.Interfaces.Paging;
using xConnected.Core.Model;
using xConnected.Core.Model.ViewModel;
using xConnected.Service;

#endregion

namespace xConnected.Web.Controllers
{
    public class ExpertProfileController : ApiController
    {
        private readonly CategoryService _categoryService;
        private readonly CategorySkillService _categorySkillService;
        private readonly CountryService _countryService;
        private readonly EducationService _educationService;
        private readonly EducationSkillService _educationSkillService;
        private readonly IndustryService _industryService;
        private readonly LanguageService _languageService;
        private readonly LanguageSkillService _languageSkillService;
        private readonly ExpertProfileService _profileService;
        private readonly TechnologyService _technologyService;
        private readonly TechnologySkillService _technologySkillService;
        private readonly UserService _userService;


        public ExpertProfileController(ExpertProfileService profileService,
                                       EducationSkillService educationSkillService,
                                       EducationService educationService,
                                       CountryService countryService,
                                       LanguageSkillService languageSkillService,
                                       TechnologySkillService technologySkillService,
                                       TechnologyService technologyService,
                                       CategorySkillService categorySkillService,
                                       CategoryService categoryService,
                                       UserService userService,
                                       LanguageService languageService,
                                       IndustryService industryService)
        {
            _profileService = profileService;
            _educationSkillService = educationSkillService;
            _educationService = educationService;
            _countryService = countryService;
            _languageSkillService = languageSkillService;
            _technologySkillService = technologySkillService;
            _technologyService = technologyService;
            _categorySkillService = categorySkillService;
            _categoryService = categoryService;
            _userService = userService;
            _languageService = languageService;
            _industryService = industryService;
        }


        public IPage<ExpertProfile> ListAdvancedSearchAll(AdvancedSearchModelProfile profileModel)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var user = _userService.GetUserByUsername(User.Identity.Name);
                //set profile model's userid to current user id 
                profileModel.UserId = profileModel.UserId == 1 ? user.Id : profileModel.UserId;

                var page = _profileService.AdvancedPagedSearchedAll(profileModel);
                var entities = page.Entities.ToList();
                //set IsAuthenticated for every expert profile to true if current user id == expert profile's userid
                foreach (var entity in entities.Where(entity => entity.UserId == user.Id))
                {
                    entity.IsAuthenticated = true;
                }
                page.Entities = entities;
                return page;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }


        public IPage<ExpertProfile> ListAdvancedSearchSome(AdvancedSearchModelProfile profileModel)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var user = _userService.GetUserByUsername(User.Identity.Name);
                //set profile model's userid to current user id 
                profileModel.UserId = profileModel.UserId == 1 ? user.Id : profileModel.UserId;

                var page = _profileService.AdvancedPagedSearchedSome(profileModel);
                var entities = page.Entities.ToList();
                //set IsAuthenticated for every expert profile to true if current user id == expert profile's userid
                foreach (var entity in entities.Where(entity => entity.UserId == user.Id))
                {
                    entity.IsAuthenticated = true;
                }
                page.Entities = entities;
                return page;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }


        public HttpResponseMessage PostExpertProfile(ExpertProfile profile)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var user = _userService.GetUserByUsername(User.Identity.Name);
                profile.User = user;

                //set profile as default if it's first user's profile
                if (user.ExpertProfiles.Count == 0 && user.CompanyProfiles.Count == 0)
                {
                    profile.IsDefault = true;
                }

                var selectedLanguageSkills = new List<LanguageSkill>(profile.LanguageSkills);
                profile.LanguageSkills.Clear();
                var selectedTechnologySkills = new List<TechnologySkill>(profile.TechnologySkills);
                profile.TechnologySkills.Clear();
                var selectedEducationSkills = new List<EducationSkill>(profile.EducationSkills);
                profile.EducationSkills.Clear();
                var selectedCategorySkills = new List<CategorySkill>(profile.CategorySkills);
                profile.CategorySkills.Clear();
                profile.Country = null;

                // first save the parent entity in order to autogenerate his Id
                _profileService.SaveOrUpdate(profile);

                 //if the profile belongs to current user save changes
                if (profile.UserId == user.Id)
                {
                    //create directories for the new profile
                    var di1 =
                        new DirectoryInfo(
                            HttpContext.Current.Server.MapPath("~/Content/Uploads/" +
                                                               Path.Combine(user.Username, "ExpertProfiles",
                                                                            profile.Id.ToString(), "Photo")));
                    di1.Create();

                    var di2 =
                        new DirectoryInfo(
                            HttpContext.Current.Server.MapPath("~/Content/Uploads/" +
                                                               Path.Combine(user.Username, "ExpertProfiles",
                                                                            profile.Id.ToString(), "Cv")));
                    di2.Create();

                    //Save Photo
                    var username = _userService.GetUserByUsername(User.Identity.Name).Username;
                    var fileNamePhoto = profile.Photo.Substring(profile.Photo.IndexOf("/250X250_") + 9);
                    var directoryPhoto =
                        HttpContext.Current.Server.MapPath("~/Content/Uploads/" +
                                                           Path.Combine(username, "ExpertProfiles",
                                                                        profile.Id.ToString(),
                                                                        "Photo"));

                    var dirPhoto = new DirectoryInfo(directoryPhoto);
                    if (!dirPhoto.Exists)
                        dirPhoto.Create();
                    foreach (var fi in dirPhoto.GetFiles())
                    {
                        if (!fi.FullName.Contains("\\250X250_" + fileNamePhoto) &&
                            !fi.FullName.Contains("\\150X150_" + fileNamePhoto) &&
                            !fi.FullName.Contains("\\80X80_" + fileNamePhoto))
                        {
                            fi.Delete();
                        }
                    }

                    //Save Cv
                    var fileNameCv = profile.Cv.Substring(profile.Cv.IndexOf("/Cv_") + 4);
                    var directoryCv =
                        HttpContext.Current.Server.MapPath("~/Content/Uploads/" +
                                                           Path.Combine(username, "ExpertProfiles",
                                                                        profile.Id.ToString(),
                                                                        "Cv"));

                    var dirCv = new DirectoryInfo(directoryCv);
                    if (!dirCv.Exists)
                        dirCv.Create();
                    foreach (var fi in dirCv.GetFiles())
                    {
                        if (!fi.FullName.Contains("\\Cv_" + fileNameCv))
                        {
                            fi.Delete();
                        }
                    }
                    // then set this Id to all his child relationships foreign key properties
                    profile.LanguageSkills = new List<LanguageSkill>(selectedLanguageSkills);
                    profile.LanguageSkills.ToList().ForEach(l => l.ExpertProfileId = profile.Id);
                    profile.TechnologySkills = new List<TechnologySkill>(selectedTechnologySkills);
                    profile.TechnologySkills.ToList().ForEach(t => t.ExpertProfileId = profile.Id);
                    profile.CategorySkills = new List<CategorySkill>(selectedCategorySkills);
                    profile.CategorySkills.ToList().ForEach(c => c.ExpertProfileId = profile.Id);
                    profile.EducationSkills = new List<EducationSkill>(selectedEducationSkills);
                    profile.EducationSkills.ToList().ForEach(e => e.ExpertProfileId = profile.Id);

                    foreach (var languageSkill in profile.LanguageSkills)
                    {
                        languageSkill.ExpertProfileId = profile.Id;
                    }
                    foreach (var technologySkill in profile.TechnologySkills)
                    {
                        technologySkill.ExpertProfileId = profile.Id;
                    }
                    foreach (var categorySkill in profile.CategorySkills)
                    {
                        categorySkill.ExpertProfileId = profile.Id;
                    }
                    foreach (var educationSkill in profile.EducationSkills)
                    {
                        educationSkill.ExpertProfileId = profile.Id;
                    }
                    _profileService.SaveOrUpdate(profile);

                    var response = Request.CreateResponse(HttpStatusCode.Created, profile.Id);
                    return response;
                }
                //else if the profile doesn't belong to current user return "error" 
                //which means to render "you are not allowed...." message on client side
                return new HttpResponseMessage(HttpStatusCode.Forbidden);
            }

            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
            }
        }

        public HttpResponseMessage UpdateExpertProfile(ExpertProfile profile)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var user = _userService.GetUserByUsername(User.Identity.Name);
                profile.User = user;
                //if the profile belongs to current user save changes
                if (profile.UserId == user.Id)
                {
                    var oldProfile = _profileService.GetById(profile.Id);

                    // load the old entity from the DB and manually set all its new property values
                    oldProfile.Title = profile.Title;
                    oldProfile.Description = profile.Description;
                    oldProfile.Website = profile.Website;
                    oldProfile.Skype = profile.Skype;
                    oldProfile.Facebook = profile.Facebook;
                    oldProfile.Twitter = profile.Twitter;
                    oldProfile.Linkedin = profile.Linkedin;
                    oldProfile.HourRate = profile.HourRate;
                    oldProfile.DailyRate = profile.DailyRate;
                    oldProfile.MonthlyRate = profile.MonthlyRate;
                    oldProfile.AnnualRate = profile.AnnualRate;
                    oldProfile.CommentRate = profile.CommentRate;
                    oldProfile.JobType = profile.JobType;
                    oldProfile.Experience = profile.Experience;
                    oldProfile.References = profile.References;
                    oldProfile.Availability = profile.Availability;
                    oldProfile.Other = profile.Other;
                    oldProfile.Location = profile.Location;
                    oldProfile.Email = profile.Email;
                    oldProfile.PhoneNumber = profile.PhoneNumber;
                    oldProfile.CountryId = profile.CountryId;

                    //Save Photo
                    var username = _userService.GetUserByUsername(User.Identity.Name).Username;
                    var fileNamePhoto = profile.Photo.Substring(profile.Photo.IndexOf("/250X250_") + 9);
                    var directoryPhoto =
                         HttpContext.Current.Server.MapPath("~/Content/Uploads/" +
                                       Path.Combine(username, "ExpertProfiles", profile.Id.ToString(), "Photo"));

                    var dirPhoto = new DirectoryInfo(directoryPhoto);
                    if (!dirPhoto.Exists)
                        dirPhoto.Create();
                    foreach (var fi in dirPhoto.GetFiles())
                    {
                        if (!fi.FullName.Contains("\\250X250_" + fileNamePhoto) &&
                            !fi.FullName.Contains("\\150X150_" + fileNamePhoto) &&
                            !fi.FullName.Contains("\\80X80_" + fileNamePhoto))
                        {
                            fi.Delete();
                        }
                    }

                    oldProfile.Photo = profile.Photo;

                    //Save Cv
                    var fileNameCv = profile.Cv.Substring(profile.Cv.IndexOf("/Cv_") + 4);
                    var directoryCv =
                         HttpContext.Current.Server.MapPath("~/Content/Uploads/" +
                                       Path.Combine(username, "ExpertProfiles", profile.Id.ToString(), "Cv"));

                    var dirCv = new DirectoryInfo(directoryCv);
                    if (!dirCv.Exists)
                        dirCv.Create();
                    foreach (var fi in dirCv.GetFiles())
                    {
                        if (!fi.FullName.Contains("\\Cv_" + fileNameCv))
                        {
                            fi.Delete();
                        }
                    }

                    oldProfile.Cv = profile.Cv;

                    // load all the new relationships from the DB
                    // listID = {1, 2, 5, 7}
                    // LS = [{Id = 1, Text = , ...}, {}
                    // select * from LS l where In (select LS.* from PP Inner join LS on PP.Id = LS.ExpertProfileId WHERE PP.ID = 3)

                    profile.LanguageSkills.ToList().ForEach(l => l.ExpertProfileId = profile.Id);

                    var lSkills = _languageSkillService.GetAll().Where(ls => ls.ExpertProfileId == oldProfile.Id);
                    lSkills.ToList().ForEach(ls => _languageSkillService.Delete(ls));

                    profile.TechnologySkills.ToList().ForEach(t => t.ExpertProfileId = profile.Id);

                    var tSkills = _technologySkillService.GetAll().Where(ts => ts.ExpertProfileId == oldProfile.Id);
                    tSkills.ToList().ForEach(ts => _technologySkillService.Delete(ts));


                    profile.CategorySkills.ToList().ForEach(l => l.ExpertProfileId = profile.Id);

                    var cSkills = _categorySkillService.GetAll().Where(cs => cs.ExpertProfileId == oldProfile.Id);
                    cSkills.ToList().ForEach(cs => _categorySkillService.Delete(cs));

                    profile.EducationSkills.ToList().ForEach(t => t.ExpertProfileId = profile.Id);

                    var eSkills = _educationSkillService.GetAll().Where(es => es.ExpertProfileId == oldProfile.Id);
                    eSkills.ToList().ForEach(es => _educationSkillService.Delete(es));

                    // clean the old relationships and set the new ones
                    oldProfile.LanguageSkills.Clear();
                    oldProfile.TechnologySkills.Clear();
                    oldProfile.EducationSkills.Clear();
                    //oldProfile.Country = null;
                    oldProfile.CategorySkills.Clear();

                    _profileService.SaveOrUpdate(oldProfile);

                    // language skills and technology skills require also to set their foreign key because
                    //they are "one to many" relationship
                    // for the "many to many" it is enough to add it to the list

                    profile.TechnologySkills.ToList().ForEach(l => oldProfile.TechnologySkills.Add(l));
                    profile.LanguageSkills.ToList().ForEach(l => oldProfile.LanguageSkills.Add(l));
                    profile.CategorySkills.ToList().ForEach(l => oldProfile.CategorySkills.Add(l));
                    profile.EducationSkills.ToList().ForEach(l => oldProfile.EducationSkills.Add(l));

                    //educations.ForEach(l => oldProfile.EducationSkills.Add(l));
                    //categories.ForEach(l => oldProfile.CategorySkills.Add(l));

                    _profileService.SaveOrUpdate(oldProfile);

                    return new HttpResponseMessage(HttpStatusCode.OK);
                }
                //else if the profile doesn't belong to current user return "error"
                //which means to render "you are not allowed...." message on client side
                return new HttpResponseMessage(HttpStatusCode.Forbidden);
            }

            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }

        public HttpResponseMessage PostDeleteExpertProfile(int profileId)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var user = _userService.GetUserByUsername(User.Identity.Name);
                var profile = _profileService.GetById(profileId);
                //if the profile belongs to current user save changes
                if (profile.UserId == user.Id)
                {
                    _profileService.Delete(profile);
                    return new HttpResponseMessage(HttpStatusCode.NoContent);
                }
                //else if the profile doesn't belong to current user return "error"
                //which means to render "you are not allowed...." message on client side
                return new HttpResponseMessage(HttpStatusCode.Forbidden);
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                return new HttpResponseMessage(HttpStatusCode.NotFound);
            }
        }

        public IEnumerable<ValueDescriptionModel> ListJobTypes()
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var jobTypes = new List<ValueDescriptionModel>
                                   {
                                       new ValueDescriptionModel
                                           {
                                               Value = 0,
                                               Description =
                                                   Resources.ResourceManager.GetString("EmploymentType0",
                                                                                       Thread.CurrentThread.
                                                                                           CurrentCulture)
                                           },
                                       new ValueDescriptionModel
                                           {
                                               Value = 1,
                                               Description =
                                                   Resources.ResourceManager.GetString("EmploymentType1",
                                                                                       Thread.CurrentThread.
                                                                                           CurrentCulture)
                                           },
                                       new ValueDescriptionModel
                                           {
                                               Value = 2,
                                               Description =
                                                   Resources.ResourceManager.GetString("EmploymentType2",
                                                                                       Thread.CurrentThread.
                                                                                           CurrentCulture)
                                           },
                                       new ValueDescriptionModel
                                           {
                                               Value = 4,
                                               Description =
                                                   Resources.ResourceManager.GetString("EmploymentType4",
                                                                                       Thread.CurrentThread.
                                                                                           CurrentCulture)
                                           },
                                       new ValueDescriptionModel
                                           {
                                               Value = 8,
                                               Description =
                                                   Resources.ResourceManager.GetString("EmploymentType8",
                                                                                       Thread.CurrentThread.
                                                                                           CurrentCulture)
                                           },
                                       new ValueDescriptionModel
                                           {
                                               Value = 16,
                                               Description =
                                                   Resources.ResourceManager.GetString("EmploymentType16",
                                                                                       Thread.CurrentThread.
                                                                                           CurrentCulture)
                                           },
                                       new ValueDescriptionModel
                                           {
                                               Value = 32,
                                               Description =
                                                   Resources.ResourceManager.GetString("EmploymentType32",
                                                                                       Thread.CurrentThread.
                                                                                           CurrentCulture)
                                           }
                                   };

                return jobTypes;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }

        public IEnumerable<ValueDescriptionModel> ListLevels()
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var levels = new List<ValueDescriptionModel>
                                 {
                                     new ValueDescriptionModel
                                         {
                                             Value = 1,
                                             Description =
                                                 Resources.ResourceManager.GetString("Basic",
                                                                                     Thread.CurrentThread.CurrentCulture)
                                         },
                                     new ValueDescriptionModel
                                         {
                                             Value = 2,
                                             Description =
                                                 Resources.ResourceManager.GetString("Intermediate",
                                                                                     Thread.CurrentThread.CurrentCulture)
                                         },
                                     new ValueDescriptionModel
                                         {
                                             Value = 3,
                                             Description =
                                                 Resources.ResourceManager.GetString("Advanced",
                                                                                     Thread.CurrentThread.CurrentCulture)
                                         },
                                     new ValueDescriptionModel
                                         {
                                             Value = 4,
                                             Description =
                                                 Resources.ResourceManager.GetString("Proficient",
                                                                                     Thread.CurrentThread.CurrentCulture)
                                         },
                                     new ValueDescriptionModel
                                         {
                                             Value = 5,
                                             Description =
                                                 Resources.ResourceManager.GetString("Professional",
                                                                                     Thread.CurrentThread.CurrentCulture)
                                         }
                                 };

                return levels;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }

        public IEnumerable<ValueDescriptionModel> ListExperiences()
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var experiences = new List<ValueDescriptionModel>
                                      {
                                          new ValueDescriptionModel
                                              {
                                                  Value = 1,
                                                  Description =
                                                      Resources.ResourceManager.GetString("LessThan1Year",
                                                                                          Thread.CurrentThread.
                                                                                              CurrentCulture)
                                              },
                                          new ValueDescriptionModel
                                              {
                                                  Value = 2,
                                                  Description =
                                                      Resources.ResourceManager.GetString("OneToThreeYears",
                                                                                          Thread.CurrentThread.
                                                                                              CurrentCulture)
                                              },
                                          new ValueDescriptionModel
                                              {
                                                  Value = 3,
                                                  Description =
                                                      Resources.ResourceManager.GetString("ThreeToFiveYears",
                                                                                          Thread.CurrentThread.
                                                                                              CurrentCulture)
                                              },
                                          new ValueDescriptionModel
                                              {
                                                  Value = 4,
                                                  Description =
                                                      Resources.ResourceManager.GetString("FiveToTenYears",
                                                                                          Thread.CurrentThread.
                                                                                              CurrentCulture)
                                              },
                                          new ValueDescriptionModel
                                              {
                                                  Value = 5,
                                                  Description =
                                                      Resources.ResourceManager.GetString("MoreThenTenYears",
                                                                                          Thread.CurrentThread.
                                                                                              CurrentCulture)
                                              }
                                      };

                return experiences;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }

        public IEnumerable<ValueDescriptionModel> ListAvailabilityStatuses()
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var availabilityStatuses = new List<ValueDescriptionModel>
                                               {
                                                   new ValueDescriptionModel
                                                       {
                                                           Value = 1,
                                                           Description =
                                                               Resources.ResourceManager.GetString(
                                                                   "AvailabilityStatus1",
                                                                   Thread.CurrentThread.
                                                                       CurrentCulture)
                                                       },
                                                   new ValueDescriptionModel
                                                       {
                                                           Value = 2,
                                                           Description =
                                                               Resources.ResourceManager.GetString(
                                                                   "AvailabilityStatus2",
                                                                   Thread.CurrentThread.
                                                                       CurrentCulture)
                                                       },
                                                   new ValueDescriptionModel
                                                       {
                                                           Value = 3,
                                                           Description =
                                                               Resources.ResourceManager.GetString(
                                                                   "AvailabilityStatus3",
                                                                   Thread.CurrentThread.
                                                                       CurrentCulture)
                                                       }
                                               };

                return availabilityStatuses;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }

        public HttpResponseMessage SetAsDefault(ExpertProfile expertProfile)
        {
            ILog log = LogManager.GetLogger(GetType());
            try
            {
                var profile = _profileService.GetById(expertProfile.Id);
                var user = profile.User;
                //set isdefault=false to all other profiles that belong to current user
                if (user.ExpertProfiles != null)
                {
                    user.ExpertProfiles.ToList().ForEach(e => e.IsDefault = false);
                }
                if (user.CompanyProfiles != null)
                {
                    user.CompanyProfiles.ToList().ForEach(c => c.IsDefault = false);
                    foreach (var project in from companyProfile in user.CompanyProfiles
                                            where companyProfile.Positions != null
                                            from project in
                                                user.CompanyProfiles.SelectMany(company => company.Positions)
                                            select project)
                    {
                        project.IsDefault = false;
                    }
                }
                profile.IsDefault = true;
                _profileService.SaveOrUpdate(profile);
                return new HttpResponseMessage(HttpStatusCode.OK);
            }
            catch (Exception ex)
            {
                log.Error(ex.Message + Environment.NewLine + "Stack: " + ex.StackTrace, ex);
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }
    }
}